﻿using IQReportes_Batch.WebService;
using IQReportes_Batch.WebService.DTO;
using IQReportes_Batch.WebService.Models;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using IQReportes_Batch.Logica;

namespace IQReportes_Batch
{
    class LogicaActualizacion
    {
        //Esto si debe ser batch TODOS LOS DIAS
        
        //primero verificar el día de hoy para saber si se deben setear los contadores del mes en cero, en el caso 
        //q sea un nuevo mes --> c/cambio de mes
        DateTime fechaActual = DateTime.Now;
        FuncionesGenericas funcionesGen = new FuncionesGenericas();
        ConexionSQL dbSQL = new ConexionSQL();
        CrearBD dbCreacion = new CrearBD();
        ParametroDAO dbParametro = new ParametroDAO();
        DateTime fechaBase = new DateTime();
        List<DIR> listaDir = new List<DIR>();
        List<DIR> nuevosDirs = new List<DIR>();
        DirDAO dbDirs = new DirDAO();
        RepresentanteComercialDAO dbReps = new RepresentanteComercialDAO();
        MotivoDAO dbMotivo = new MotivoDAO();
        Dictionary<string, Ubigeo> diccionAuxUbi = new Dictionary<string, Ubigeo>();
        Dictionary<string,RepresentanteComercial> diccionarioRepresentantes = new Dictionary<string,RepresentanteComercial>();
        Dictionary<string, Motivo> diccionarioMotivos = new Dictionary<string, Motivo>();
        Dictionary<string, DIR> diccionrioDirs = new Dictionary<string, DIR>();
        LogicaParametro logicaParametro = new LogicaParametro();
        UbigeoDAO dbUbigeo = new UbigeoDAO();

        //Primero actualizar los consolidados de dia, semana, mes y año según corresponda
        public void actualizarConsolidados()
        {
            try
            {
                DateTime fechaAux;
                var estadoBatch = dbParametro.parametros.Where(a => a.vcNombre == "EstadoBatch").First();
                DateTime fechaOrigen = funcionesGen.convertirStringToFecha(estadoBatch.vcValor, "dd/MM/yyyy");
                DateTime fechaActual = funcionesGen.convertirStringToFecha(DateTime.Now.ToString("dd/MM/yyyy"), "dd/MM/yyyy");
                int diasAtraso = fechaActual.Subtract(fechaOrigen).Days;
                for (int i = diasAtraso - 1; i >= 1; i--)
                {
                    fechaBase = DateTime.Now.AddDays(-i);
                    Console.WriteLine("se inicio recuperador mes para el dia " + fechaBase.ToString("dd/MM/yyyy"));
                    //Console.WriteLine("se inicio para el dia " + fechaBase.ToString("dd/MM/yyyy"));
                    //if (llamarWebServices())
                    //{
                    //    Console.WriteLine("Entro a ws");
                    //    fechaAux = DateTime.Now.AddDays(-i - 1);
                    //    crearConsolidadoNuevosDIRs(nuevosDirs, fechaAux);
                    //}

                    //verificarDia(fechaBase);
                    //Console.WriteLine("Termino verifica dia");
                    //verificarSemana(fechaBase);
                    //Console.WriteLine("Termino verifica semana");
                    verificarMes(fechaBase);
                    Console.WriteLine("Termino verifica mes");
                    verificarAno(fechaBase);
                    Console.WriteLine("Termino verifica año");
                    estadoBatch.vcValor = fechaBase.ToString("dd/MM/yyyy");
                    dbParametro.Entry(estadoBatch).State = EntityState.Modified;
                    dbParametro.SaveChanges();
                    Console.WriteLine("termino el dia");
                    //break;   
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("hubo un error: " + e.Message);
                Console.ReadKey();
            }
        }

        private void cargaRepresentantes()
        {
            var reps = dbReps.representantes;
            diccionarioRepresentantes = new Dictionary<string, RepresentanteComercial>();
            try
            {
                foreach (var r in reps)
                {
                    diccionarioRepresentantes.Add(r.vcCodRepresentante, r);
                }
            }
            catch (Exception e)
            {
                string gg = e.Message;
            }
        }

        private void cargaMotivos()
        {
            var motivos = dbMotivo.motivos;
            diccionarioMotivos = new Dictionary<string,Motivo>();
            try
            {
                foreach (var m in motivos)
                {
                    diccionarioMotivos.Add(m.vcCodMotivo, m);
                }
            }
            catch(Exception e)
            {
                string gg = e.Message;
            }
        }

        private void cargaDIRs()
        {
            var ddirs = dbDirs.dirs;
            try
            {
                foreach (var d in ddirs)
                {
                    diccionrioDirs.Add(d.vcCodDIR, d);
                }
            }
            catch (Exception e)
            {
                string gg = e.Message;
            }
        }

        /*private void parsearMotivo(Motivo motivoLocal, MotivoModelService motivoWS)
        {
            if (motivoWS.codMotivo != null && !Constantes.CADENA_VACIA.Equals(motivoWS.codMotivo))
            {
                motivoLocal.vcCodMotivo = motivoWS.codMotivo;    
            }

            if (motivoWS.motivo != null && !Constantes.CADENA_VACIA.Equals(motivoWS.motivo))
            {
                motivoLocal.vcMotivo = motivoWS.motivo;
            }
            
        }*/

        private void parsearRepresentante(RepresentanteComercial repLocal, RepresentanteModelService repWS)
        {
            if (repWS.codRepresentante != null && !Constantes.CADENA_VACIA.Equals(repWS.codRepresentante))
            {
                repLocal.vcCodRepresentante = repWS.codRepresentante;
            }
            if (repWS.nombres != null && !Constantes.CADENA_VACIA.Equals(repWS.nombres))
            {
                repLocal.vcNombreCompleto = repWS.nombres;
            }
            
        }

        private void parsearDir(DIR dirLocal, DIRModelService dirWS)
        {
            dirLocal.inEstado = dirWS.estado;
            if(dirWS.getCodigoMotivo() !=null && !Constantes.CADENA_VACIA.Equals(dirWS.getCodigoMotivo())){
                if (diccionarioMotivos.ContainsKey(dirWS.getCodigoMotivo())) {
                    dirLocal.idMotivo = diccionarioMotivos[dirWS.getCodigoMotivo()].idMotivo;
                }
            }

            if (dirWS.codRepresentante != null && !Constantes.CADENA_VACIA.Equals(dirWS.codRepresentante))
            {
                if (diccionarioRepresentantes.ContainsKey(dirWS.codRepresentante))
                {
                    dirLocal.idRepresentante = diccionarioRepresentantes[dirWS.codRepresentante].idRepresentante;
                }
            }

            if (dirWS.codTienda != null && !Constantes.CADENA_VACIA.Equals(dirWS.codTienda))
            {
                dirLocal.vcCodTienda = dirWS.codTienda;
            }

            if (dirWS.nombreTienda != null && !Constantes.CADENA_VACIA.Equals(dirWS.nombreTienda))
            {
                dirLocal.vcNombreTienda = dirWS.nombreTienda;
            }

            if (dirWS.codUbigeo != null && !Constantes.CADENA_VACIA.Equals(dirWS.codUbigeo))
            {
                dirLocal.vcCodDistrito = dirWS.codUbigeo;
            }

            if (dirWS.codLocal != null && !Constantes.CADENA_VACIA.Equals(dirWS.codLocal))
            {
                dirLocal.vcCodLocal = dirWS.codLocal;
            }

            if (dirWS.nombreLocal != null && !Constantes.CADENA_VACIA.Equals(dirWS.nombreLocal))
            {
                dirLocal.vcLocal = dirWS.nombreLocal;
            }
        }

        public bool llamarWebServices()
        {
            ConsumeRestService cliente = new ConsumeRestService();
                      
            actualizarRepresentantes(cliente);
            actualizarDIRs(cliente);

            if (nuevosDirs != null && nuevosDirs.Count()>0)
            {
                return true;
            }
            else
            {
                return false;
            }
                        
        }


        private void actualizarRepresentantes(ConsumeRestService cliente)
        {
            try
            {
                RepresentanteComercial repTemp;
                var representantesWS = cliente.getRepresentantes();
                cargaRepresentantes();
                if (representantesWS != null)
                {
                    foreach (var r in representantesWS)
                    {
                        repTemp = new RepresentanteComercial();
                        if (diccionarioRepresentantes.ContainsKey(r.codRepresentante)) //si en la bd existe el representante
                        {
                            repTemp = diccionarioRepresentantes[r.codRepresentante];
                            parsearRepresentante(repTemp, r);
                            dbReps.Entry(repTemp).State = EntityState.Modified;
                            dbReps.SaveChanges();
                        }
                        else
                        {
                            parsearRepresentante(repTemp, r);
                            dbReps.representantes.Add(repTemp);
                            dbReps.SaveChanges();
                        }
                    }
                }
            }
            catch (Exception e)
            {

            }
        }


        public void generarUbigeoDIR(DIR d)
        {
 
            d.vcDistrito = diccionAuxUbi[d.vcCodDistrito].vcDistrito;
            d.vcProvincia = diccionAuxUbi[d.vcCodDistrito].vcProvincia;
            d.vcDepartamento = diccionAuxUbi[d.vcCodDistrito].vcDepartamento;
                
        }

        private void cargaUbiges()
        {
            var listaUbi = dbUbigeo.ubigeos;
            
            foreach (Ubigeo u in listaUbi)
            {
                diccionAuxUbi.Add(u.vcCodDistrito, u);
            }
        }

        private void actualizarDIRs(ConsumeRestService cliente)
        {
            try
            {
                DIR dirTemp;
                var dirsWS = cliente.getDirs();
                //var dirWSAux = dirsWS.Where(a => a.estado != 0);
                cargaRepresentantes();
                cargaMotivos();
                cargaDIRs();
                cargaUbiges();

                if (dirsWS != null)
                {
                    foreach (var d in dirsWS)
                    {

                        if (diccionrioDirs.ContainsKey(d.codDir)) //si en la bd actual existe el dir
                        {
                            dirTemp = new DIR();
                            dirTemp = diccionrioDirs[d.codDir];
                            parsearDir(dirTemp, d);
                            
                            dbDirs.Entry(dirTemp).State = EntityState.Modified;
                            dbDirs.SaveChanges();
                        }
                        else //si no existe
                        {
                            dirTemp = new DIR();
                            dirTemp.vcCodDIR = d.codDir;
                            parsearDir(dirTemp, d);
                            generarUbigeoDIR(dirTemp);
                            dbDirs.dirs.Add(dirTemp);
                            dbDirs.SaveChanges();
                            nuevosDirs.Add(dirTemp); //estos nuevos dirs son los que van a ir para crear los nuevos consolidados
                        }
                    }
                    DateTime fechaInvocacion = DateTime.Now;
                    logicaParametro.actualizarFechaWSDir(fechaInvocacion);
                }
                
            }
            catch (Exception e)
            {

            }
        }
        //Se encarga de crear los consolidados de dia, semana, mes y año cada uno de los dirs que recibe.
        private void crearConsolidadoNuevosDIRs(List<DIR> dirs,DateTime fecha)
        {
            if(dirs.Count()>0){
                
                dbCreacion.generarTablaConsolidadoInicial(fecha, Constantes.IBK_TBL_CONS_ANO, 0, dirs);
                for (int i = 0; i < Constantes.UNI_MAX_ANTIGUEDAD_MES; i++)
                {
                    dbCreacion.generarTablaConsolidadoInicial(fecha, Constantes.IBK_TBL_CONS_MES, i, dirs);
                }
                for (int i = 0; i < Constantes.UNI_MAX_ANTIGUEDAD_SEMANA; i++)
                {
                    dbCreacion.generarTablaConsolidadoInicial(fecha, Constantes.IBK_TBL_CONS_SEMANA, i, dirs);
                }
                for (int i = 0; i < Constantes.UNI_MAX_ANTIGUEDAD_DIA; i++)
                {
                    dbCreacion.generarTablaConsolidadoInicial(fecha, Constantes.IBK_TBL_CONS_DIA, i, dirs);
                }
            }
        }

        
        private bool obtenerFechaBase()
        {
            DateTime fecha;
            fecha = DateTime.Now;
            try
            {
                var parametro = dbParametro.parametros.Where(a => a.vcNombre == "DiasFinalTx").First();
                fechaBase = fecha.AddDays(-parametro.inValor);
                return true;
            }
            catch (Exception e)
            {
                string gg = e.Message;
                return false;
            }
        }

        //Verifica si la fecha obtenida es el primer día del mes. En el caso así fuese lo que hace es verificar
        //Que no haya el mismo mes el año anterior. En caso que hubiese se debe de invocar a los stored proc
        //que se encarguen de actualizar la data de dicho mes en los consolidados.
        private void verificarMes(DateTime fecha)
        {
            int mes,ano,dia,unidadAntiguedad;
            string stMes;
            DataSet ds;
            List<FormatoFecha> listaFechas;
            List<SqlParameter> listaParametros;
            dia = fecha.Day;
            
            //si es el primer dia del mes entonces hay que actualizar el consolidado de meses
            if (dia == 1)
            {
                mes = fecha.Month;
                stMes = funcionesGen.calcularMes(fecha);
                ano = fecha.Year;
                
                unidadAntiguedad = Constantes.UNI_MAX_ANTIGUEDAD_MES;

                //preparando la consulta a bd para observar el año y mes
                ds = new DataSet();
                listaParametros = new List<SqlParameter>();
                SqlParameter param1 = new SqlParameter("@unidadesAntiguedad", SqlDbType.Int);
                param1.Value = unidadAntiguedad;
                listaParametros.Add(param1);

                dbSQL.ejecutarSelectProcedureDS(ProcedimientosAlmacenados.obtener_mes_ano_x_antiguedad, listaParametros, ds);
                //ejecutando el stored procedure

                listaFechas = new List<FormatoFecha>();
                obtenerDSMesXAno(ds, listaFechas, Constantes.CODIGO_MES);

                //si existe el mismo mes para el año pasado en la tabla de consolidado mes entonces comenzamos
                if (listaFechas[0].ano == (ano - 1) && listaFechas[0].mes.Equals(stMes))
                {
                    string tabla;
                    listaParametros = new List<SqlParameter>();
                    SqlParameter param = new SqlParameter("@codTabla", SqlDbType.Int);
                    param.Value = Constantes.CODIGO_MES;
                    listaParametros.Add(param);
                    tabla = Constantes.IBK_TBL_CONS_MES;
                    ejecutarActualizacionConsolidado(listaParametros, tabla, fecha);
                }
            }
        }


        //Esta acción se realiza a diario. Llama a los stored procedures que se encargan de 
        //actualizar la data de los consolidados diarios.
        private void verificarDia(DateTime fecha)
        {            
            List<SqlParameter> listaParametros;
            string tabla;
            //si se deben borrar los datos de una dia-->esto hace el proceso batc diario
            listaParametros = new List<SqlParameter>();
            SqlParameter param1 = new SqlParameter("@codTabla", SqlDbType.Int);
            param1.Value = Constantes.CODIGO_DIA;
            listaParametros.Add(param1);
            tabla = Constantes.IBK_TBL_CONS_DIA;

            ejecutarActualizacionConsolidado(listaParametros, tabla, fecha);
            
        }

        private void verificarAno(DateTime fecha)
        {
            List<SqlParameter> listaParametros1; DataSet ds;
            List<SqlParameter> listaParametros2;
            List<FormatoFecha> listaFechas = new List<FormatoFecha>();
            int anoMax;
                       
            string tabla;
            int mes = fecha.Month;
            int dia = fecha.Day;
            if (mes == 1 && dia == 1)
            {
                ds = new DataSet();
                listaParametros1 = new List<SqlParameter>();
                dbSQL.ejecutarSelectProcedureDS(ProcedimientosAlmacenados.obtener_anos_consolidado, listaParametros1, ds);

                obtenerDSMesXAno(ds, listaFechas, Constantes.CODIGO_ANO);
                anoMax = listaFechas.AsQueryable().Max(a => a.ano);

                //pasamos a una segunda verificacion sobre el año.
                if (anoMax < fecha.Year)
                {
                    listaParametros2 = new List<SqlParameter>();
                    SqlParameter param1 = new SqlParameter("@codTabla", SqlDbType.Int);
                    param1.Value = Constantes.CODIGO_ANO;
                    listaParametros2.Add(param1);
                    tabla = Constantes.IBK_TBL_CONS_ANO;

                    ejecutarActualizacionConsolidado(listaParametros2, tabla, fecha);
                }
            }
        }

        //Verifica si la fecha obtenida corresponde al primer día de la semana (domingo)
        //En caso que asi sea, se debe de invocar a los stored proc
        //que se encarguen de actualizar la data de dicho de los consolidados semanales.
        private void verificarSemana(DateTime fecha)
        {
            //si se debe borrar los datos de una semana --> esto hace el proceso batch los domingos(cada cambio de semana)
            if (DayOfWeek.Sunday == fechaBase.DayOfWeek)
            {
                List<SqlParameter> listaParametros;
                listaParametros = new List<SqlParameter>();
                string tabla;
                SqlParameter param1 = new SqlParameter("@codTabla", SqlDbType.Int);
                param1.Value = Constantes.CODIGO_SEMANA;
                listaParametros.Add(param1);
                tabla = Constantes.IBK_TBL_CONS_SEMANA;
                ejecutarActualizacionConsolidado(listaParametros, tabla, fecha);
            }
        }

        private void ejecutarActualizacionConsolidado(List<SqlParameter> listaParametros, string tabla,DateTime fecha)
        {
            
            if (!Constantes.IBK_TBL_CONS_ANO.Equals(tabla) && !Constantes.BCP_TBL_CONS_ANO.Equals(tabla))
            {
                //borrar el que tiene mayor antiguedad
                dbSQL.ejecturarNoReaderProcedure(listaParametros, ProcedimientosAlmacenados.elimina_mayor_antiguedad_consolidado);
                //agregar una unidad a las unidades antiguedad
                dbSQL.ejecturarNoReaderProcedure(listaParametros, ProcedimientosAlmacenados.actualiza_unidad_x_antiguedad);
                //crear los nuevos registros
            }
            listaDir = dbDirs.dirs.ToList();
            dbCreacion.generarTablaConsolidadoInicial(fecha, tabla, 0,listaDir);
            
        }


        private void obtenerDSMesXAno(DataSet ds, List<FormatoFecha> listaFechas, int codigoFecha)
        {
            FormatoFecha elementoFecha;
            int i = 0;
            foreach (DataRow dr in ds.Tables[0].Rows)
            {
                elementoFecha = new FormatoFecha();
                elementoFecha.ano = Int32.Parse(dr[i].ToString()); i++;
                if (codigoFecha == Constantes.CODIGO_MES)
                {
                    elementoFecha.mes = dr[i].ToString(); i++;
                }
                if (codigoFecha == Constantes.CODIGO_SEMANA)
                {
                    elementoFecha.semana = dr[i].ToString();
                }
                i = 0;
                listaFechas.Add(elementoFecha);
            }
        }
    }
}       
